#ifndef __M_SERVICE_H__
#define __M_SERVICE_H__

#include "data.hpp"
#include "conf.hpp"
#include "httplib.h"
#include <string>
#include <vector>
#include <sstream>
#include <ctime>

extern Cloud::DataManage *_data; // 声明使用外部变量

namespace Cloud
{
    class Service
    {
    public:
        Service()
        {
            Config *pc = Config::GetInstance();
            _server_ip = "0.0.0.0";
            _server_port = pc->GetServerPort();
            _download_prefix = pc->GetDownLoadPrefix();
        }

        bool RunModule()
        {
            // 给不同的请求注册对应的方法
            _server.Post("/upload", UpLoad);
            _server.Get("/listshow", ListShow);
            _server.Get("/", ListShow);
            std::string downloadURL = _download_prefix + "(.*)";
            _server.Get(downloadURL, DownLoad);

            _server.listen(_server_ip.c_str(), _server_port);

            return true;
        }



    private:
        static void UpLoad(const httplib::Request &req, httplib::Response &rsp)
        {
            // 判断有没有 file 字段（其中包含上传的文件内容）
            auto ret = req.has_file("file");
            if(ret == false)
            {
                rsp.status = 400;
                return;
            }

            // 生成上传文件真实路径
            const auto& file = req.get_file_value("file");
            std::string backDir = Config::GetInstance()->GetBackFileDir();

            std::string filename = FileUtil(file.filename).FileName();

            // 将文件名编码从 gbk 转换为 utf8
            filename = EncodingConver().GBKToUTF8(filename);

            std::string realPath = backDir + filename;

            std::cout << "准备上传文件: " << realPath << std::endl;

            std::string cont = file.content;

            // 加载文件数据
            FileUtil fu(realPath);
            fu.SetContent(cont);

            // 注册文件信息
            BackedInfo info(realPath);

            _data->Insert(info);

            rsp.status = 200;
        }

        static std::string TimeToStr(time_t time)
        {
            // 将时间戳转换为指定格式的时间字符串
            //   Wed Feb 13 16:06:10 2013
            return ctime(&time);
        }

        static void ListShow(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1.获取所有文件的备份信息
            std::vector<BackedInfo> array;
            _data->GetAll(&array);

            // 2.根据信息组织 HTML 页面
            std::stringstream ss;
            ss << R"(<html><head><meta charset = "utf-8"><title>Download</title></head><body><h1>Download</h1><table>)";
            for(auto &info : array)
            {
                std::string filename = FileUtil(info.real_path).FileName();
                ss << "<tr>";
                ss << R"(<td><a href=")" << info.url << R"(">)" << filename << "</a></td>";
                ss << R"(<td align="right">)" << TimeToStr(info.mtime) <<  "</td>";
                ss << R"(<td align="right">)" << info.fsize / 1024 << "k</td>";
                ss << "</tr>";
            }
            ss << "</table></body></html>";

            rsp.body = ss.str().c_str();

            rsp.set_header("Content-Type", "text/html");
            rsp.status = 200;
        }

        // 获取 ETag 文件唯一标识符
        static std::string GetETag(const BackedInfo &info)
        {
            std::string etag;
            etag += FileUtil(info.real_path).FileName();
            etag += "-";
            etag += std::to_string(info.fsize);
            etag += "-";
            etag += std::to_string(info.mtime);

            return etag;
        }
    
        // 字符串分割，将 str 按照 sep 作为分割符进行分割
        static bool strSplit(const std::string &str, const std::string &sep, std::vector<std::string> *pa)
        {
            size_t left = 0; // 指向分割区间的左端点
            size_t right = 0; // 指向分割区间的右端点
            while(right < str.size())
            {
                right = str.find(sep, left);

                if(right == std::string::npos)
                    break;
                
                // 切割字符
                pa->push_back(str.substr(left, right - left));
                left = right + sep.size();
            }

            if(left < str.size())
                pa->push_back(str.substr(left));
            
            return true;
        }

        static void DownLoad(const httplib::Request &req, httplib::Response &rsp)
        {
            // 1. 获取客户端请求的资源路径
            std::string url = req.path;

            // 2.根据资源路径获取文件备份信息
            BackedInfo info;
            if(_data->GetOneByURL(url, &info) == false)
            {
                std::cerr << "DownLoad get fileinfo fail!" << std::endl;
                return;
            }

            // 3.判断文件是否被压缩
            if(info.pack_flag == true)
            {
                FileUtil fu(info.pack_path);

                // 3.1 解压
                fu.UnCompress(info.real_path);

                // 3.2 删除压缩包
                fu.Remove();

                // 3.3 更新备份信息
                info.pack_flag = false;
                _data->Update(info);
            }

            // 4.读取文件数据至响应体中
            FileUtil fu(info.real_path);
            std::string body;
            if(fu.GetContent(&body) == false)
                std::cerr << "DownLoad file empty!" << std::endl;
            rsp.body = body; // 读取数据至 rsp.body 中

            // 5.设置响应头部字段
            std::string ETag = GetETag(info);
            rsp.content_length_ = body.size();
            rsp.set_header("ETag", ETag);
            rsp.set_header("Accept-Ranges", "bytes");
            rsp.set_header("Content-Type", "application/octet-stream");
            
            // 判断是否为断点续传（由 httplib 实现，只需修改状态码即可）
            std::string OldETag = req.get_header_value("If-Range");
            if(OldETag == ETag)
                rsp.status = 206; // 206 表示区间传输成功
            else
                rsp.status = 200;
        }

    private:
        std::string _server_ip;
        int _server_port;
        std::string _download_prefix; // 下载请求前缀
        httplib::Server _server;
    };
}

#endif
